﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace Battle.View
{
    public class BattleCamera : MonoBehaviour
    {
        enum State
        {
            None,
            Attack,
            Defend
        }

        #region instance
        private static BattleCamera instance;
        public static BattleCamera Instance
        {
            get
            {
                return instance;
            }
        }
        public void Awake()
        {
            instance = this;
            battleCamera = curCamera.GetComponent<Camera>();
        }
        #endregion

        public Transform tmpTransform;

        public Transform curAxis;
        public Transform curCamera;

        public Transform targetAxis;
        public Transform targetCamera;

        public TweenAction tweenComponet;

        public FocusCamera focusCamera;
        public FocusCamera onlyFocusCamera;
        public GameObject blackPlane;

        private State curState = State.None;
        public Camera battleCamera;

        private BattleCamp ultimateCamp;

        #region params

        public float actorHeight;           //人物高度


        public float readyCameraZPosition;          //准备状态的最近镜头深度
        public Vector3 readyAxisPosition;   //准备状态的轴位置
        public Vector3 readyAxisRotation;   //准备状态的轴方向
        public float readyActorBound;      //人物范围
        public float readyMoveTime;

        public float attackCameraZPosition;          //准备状态的最近镜头深度
        public Vector3 attackAxisRotation;       //攻击时的轴旋转
        public float attackActorBound;      //人物范围

        public float defendCameraZPosition;          //准备状态的最近镜头深度
        public Vector3 defendAxisRotation;       //攻击时的轴旋转
        public float defendAxisOffset;      //整体下移
        public float defendActorBound;      //人物范围

        public Vector3 ultimateEndAxisPosition; //大招结束时轴的初始位置
        public Vector3 ultimateEndAxisRotation; //大招结束时轴的初始旋转
        public float ultimateEndCameraZPoition; //大招结束时镜头的初始大小

        public Vector3 ultimateEndDefenderAxisPosition; //大招结束时轴的初始位置
        public Vector3 ultimateEndDefenderAxisRotation; //大招结束时轴的初始旋转
        public float ultimateEndDefenderCameraZPoition; //大招结束时镜头的初始大小

        public Vector3 ultimateEndAllAxisPosition; //大招结束时轴的初始位置
        public Vector3 ultimateEndAllAxisRotation; //大招结束时轴的初始旋转
        public float ultimateEndAllCameraZPoition; //大招结束时镜头的初始大小

        public Vector3 winAxisPosition;
        public Vector3 winAxisRotation1;
        public Vector3 winAxisRotation2;
        public float winCameraZPosition1;
        public float winCameraZPosition2;
        public float winTime1;
        public float winTime2;

        public float switchCampCameraZPosition;          //准备状态的最近镜头深度
        public Vector3 switchCampAxisPosition;   //准备状态的轴位置
        public Vector3 switchCampAxisRotation;   //准备状态的轴方向
        public float switchCampMoveTime;

        public AnimationCurve curveEaseOut;
        public AnimationCurve curveEaseInOut;

        public AnimationCurve shakeCurveX;
        public AnimationCurve shakeCurveY;
        public AnimationCurve shakeCurveZ;
        public AnimationCurve shakeLargeCurveX;
        public AnimationCurve shakeLargeCurveY;
        public AnimationCurve shakeLargeCurveZ;
        public int shakeState = 0;
        public float shakeTimer = 0;

        #endregion

        #region update

        // Update is called once per frame
        void Update()
        {
            if(StaticData.currentSceneType != SceneType.BATTLE)
            {
                return;
            }
            if (Time.timeScale == 0)
            {
                return;
            }
            switch (curState)
            {
                case State.None:
                    break;
                case State.Attack:
                    UpdateAttack();
                    break;
                case State.Defend:
                    UpdateDefend();
                    break;
            }
            if (curState != State.None)
            {
                UpdateMoveToTarget();
            }

        }
        public void LateUpdate()
        {
            if (shakeState == 1)
            {
                if (shakeTimer >= shakeCurveX.keys[shakeCurveX.keys.Length - 1].time)
                {
                    shakeState = 0;
                }
                if(Time.deltaTime>0f)
                {
                    curCamera.localPosition += new Vector3(shakeCurveX.Evaluate(shakeTimer),
                    shakeCurveY.Evaluate(shakeTimer), shakeCurveZ.Evaluate(shakeTimer));
                }
                shakeTimer += Time.deltaTime;

            }
            else if (shakeState == 2)
            {
                if (shakeTimer >= shakeLargeCurveX.keys[shakeLargeCurveX.keys.Length - 1].time)
                {
                    shakeState = 0;
                }
                if (Time.deltaTime > 0f)
                {
                    curCamera.localPosition += new Vector3(shakeLargeCurveX.Evaluate(shakeTimer),
                    shakeLargeCurveY.Evaluate(shakeTimer), shakeLargeCurveY.Evaluate(shakeTimer));
                }
                
                shakeTimer += Time.deltaTime;
            }
        }
        void UpdateMoveToTarget()
        {
            Vector3 delta;

            delta = targetAxis.localPosition - curAxis.localPosition;
            delta *= Time.deltaTime * 4;// Mathf.Sqrt(delta.sqrMagnitude);
            curAxis.localPosition += delta;

            delta = GetNearAngle(targetAxis.localEulerAngles - curAxis.localEulerAngles);
            delta *= Time.deltaTime * 4;
            curAxis.localEulerAngles += delta;

            delta = targetCamera.localPosition - curCamera.localPosition;
            delta *= Time.deltaTime * 4;// * Mathf.Sqrt(delta.sqrMagnitude);
            curCamera.localPosition += delta;

            delta = GetNearAngle(targetCamera.localEulerAngles - curCamera.localEulerAngles);
            delta *= Time.deltaTime * 4;
            curCamera.localEulerAngles += delta;
        }

        private List<BattleCharacter> attackActors = new List<BattleCharacter>();
        private List<BattleCharacter> readyActors = new List<BattleCharacter>();
        private List<BattleCharacter> defendActors = new List<BattleCharacter>();
        private List<BattleCharacter> forwardActors = new List<BattleCharacter>();
        private List<BattleCharacter> backwardActors = new List<BattleCharacter>();

        List<BattleCharacter> activeActors = new List<BattleCharacter>();

        void UpdateAttack()
        {
            var battleView = GetBattleViewCtrl();
            var allActors = battleView.GetAllActors();

            Vector3 defendSumPosition = Vector3.zero;
            float defendNum = 0;
            defendActors.Clear();


            BattleCharacter attackerRight =null;
            BattleCharacter attackerLeft =null;
            //Vector3 attackSumPosition = Vector3.zero;

            float attackNum = 0;
            float healNum = 0;
            attackActors.Clear();

            Vector3 readySumPosition = Vector3.zero;
            float readyNum = 0;
            readyActors.Clear();

            Vector3 forwardSumPosition = Vector3.zero;
            float forwardNum = 0;
            forwardActors.Clear();

            Vector3 backwardSumPosition = Vector3.zero;
            float backwardNum = 0;
            backwardActors.Clear();

            var enumerator = allActors.GetEnumerator();
            while (enumerator.MoveNext())
            {
                var actor = enumerator.Current.Value;

                switch (actor.GetCurrrentStateType())
                {
                    case ActorState.Attack:
                    case ActorState.AttackWait:


                        //if (actor.GetBeFoundBonePosition().x > attackPositionRight.x)
                        //{
                        //    attackPositionRight = actor.GetBeFoundBonePosition().x;
                        //    //attackActors.Add(actor);
                        //    //attackSumPosition += actor.GetBeFoundBonePosition();
                        //    //attackNum += 1f;
                        //}
                        //if (actor.GetBeFoundBonePosition().x < attackPositionLeft.y)
                        //{
                        //    attackPositionLeft = actor.GetBeFoundBonePosition().x;
                        //    //attackActors.Add(actor);
                        //    //attackSumPosition += actor.GetBeFoundBonePosition();
                        //    //attackNum += 1f;
                        //}
                        if (attackerLeft == null || attackerLeft.GetBeFoundBonePosition().z < actor.GetBeFoundBonePosition().z)
                        {
                            attackerLeft = actor;
                        }
                        if (attackerRight == null || attackerRight.GetBeFoundBonePosition().z > actor.GetBeFoundBonePosition().z)
                        {
                            attackerRight = actor;
                        }
                        attackNum++;
                        break;
                    case ActorState.AttackMoveForward:
                        forwardActors.Add(actor);
                        forwardSumPosition += actor.GetBeFoundBonePosition();
                        forwardNum += 1f;
                        break;
                    case ActorState.AttackMoveBackward:
                        backwardActors.Add(actor);
                        backwardSumPosition += actor.GetBeFoundBonePosition();
                        backwardNum += 1f;
                        break;
                    case ActorState.AttackReady:
                        readyActors.Add(actor);
                        readySumPosition += actor.GetBeFoundBonePosition();
                        readyNum += 1f;
                        break;
                    case ActorState.Defend:
                        var state = actor.GetCurrentState() as BCDefendState;
                        if (state.defendState != DefendState.IDLE)
                        {
                            defendSumPosition += actor.GetBeFoundBonePosition() * 0.4f;
                            defendNum += 0.4f;
                        }
                        else
                        {
                            defendSumPosition += actor.GetBeFoundBonePosition() * 0.3f;
                            defendNum += 0.3f;
                        }
                        defendActors.Add(actor);
                        break;
                }
                if (actor.isHealer)
                    healNum += 1;
            }
            if (backwardNum > 0 && attackNum + forwardNum == 0)
            {
                //最后一个人后退
                Reset();
                PlayMoveToReady();
                return;
            }

            if (defendNum == 0f)
            {
                return;
            }

            activeActors.Clear();
            Vector3 averagePosition = Vector3.zero;
            float totalWeight = 0;

            if (attackNum > 0)
            {
                //averagePosition += attackSumPosition * ((1.5f - 0.5f / attackNum) / attackNum);
                //totalWeight += (1.5f - 0.5f / attackNum);
                averagePosition += attackerLeft.GetBeFoundBonePosition() * 0.0f + attackerRight.GetBeFoundBonePosition() * 0.8f;
                totalWeight += 0.8f;
                attackActors.Add(attackerLeft);
                if(attackerLeft!=attackerRight)
                {
                    attackActors.Add(attackerRight);
                }
                activeActors.AddRange(attackActors);
            }
            if (defendNum > 0 && ((attackNum + forwardNum + backwardNum - healNum) > 0))
            {
                averagePosition += defendSumPosition / defendNum * 1.2f;
                totalWeight += 1.2f;
                activeActors.AddRange(defendActors);
            }
            if (healNum > 0 && readyNum > 0)
            {
                averagePosition += readySumPosition * (0.3f / readyNum);
                totalWeight += 0.3f;
                activeActors.AddRange(readyActors);
            }
            if (attackNum == 0)
            {
                averagePosition += forwardSumPosition;
                totalWeight += forwardNum;
                activeActors.AddRange(forwardActors);
            }

            if (attackNum == 0 && forwardNum == 0)
            {
                averagePosition += backwardSumPosition;
                totalWeight += backwardNum;
                activeActors.AddRange(backwardActors);
            }

            if (activeActors.Count == 0)
                return;

            averagePosition /= totalWeight;
            averagePosition.y += actorHeight;
            averagePosition.z *= 1f;

            targetAxis.position = new Vector3(averagePosition.x, actorHeight, averagePosition.z);

            //Vector3 leftAxisPos = Vector3.zero;
            //Vector3 rightAxisPos = Vector3.zero;
            //GetBounds(activeActors, targetAxis, out leftAxisPos, out rightAxisPos);

            //float halfFOV = (battleCamera.fieldOfView * 0.5f) * Mathf.Deg2Rad;
            //float aspect = battleCamera.aspect;

            //float k = Mathf.Tan(halfFOV) * aspect;
            //float cameraZAxisPos = Mathf.Min(leftAxisPos.z - (leftAxisPos.x - attackActorBound) / (-k), rightAxisPos.z - (rightAxisPos.x + attackActorBound) / k);
            //cameraZAxisPos = Mathf.Min(cameraZAxisPos, attackCameraZPosition);

            float cameraZAxisPos = GetCameraBattleZPos(activeActors);
            cameraZAxisPos = Mathf.Min(cameraZAxisPos, attackCameraZPosition + (attackNum <= 1 ? 0:(-2f)));
            targetCamera.localPosition = new Vector3(0, 0, cameraZAxisPos);

            float sumHeight = 0;
            for (int i = 0; i < activeActors.Count; i++)
            {
                var actor = activeActors[i];
                float height = actor.GetBeFoundBonePosition().y;
                sumHeight += height;
            }
            averagePosition.y = sumHeight / activeActors.Count;
            targetCamera.LookAt(averagePosition);

        }

        void UpdateDefend()
        {
            var battleView = GetBattleViewCtrl();
            var allActors = battleView.GetAllActors();

            Vector3 defendSumPosition = Vector3.zero;
            float defendNum = 0;
            defendActors.Clear();

            Vector3 attackSumPosition = Vector3.zero;
            float attackNum = 0;
            float healNum = 0;
            attackActors.Clear();

            Vector3 readySumPosition = Vector3.zero;
            float readyNum = 0;
            readyActors.Clear();

            Vector3 forwardSumPosition = Vector3.zero;
            float forwardNum = 0;
            forwardActors.Clear();

            Vector3 backwardSumPosition = Vector3.zero;
            float backwardNum = 0;
            backwardActors.Clear();

            var enumerator = allActors.GetEnumerator();
            while (enumerator.MoveNext())
            {
                var actor = enumerator.Current.Value;
                switch (actor.GetCurrrentStateType())
                {
                    case ActorState.Attack:
                    case ActorState.AttackWait:
                        attackActors.Add(actor);
                        attackSumPosition += actor.GetBeFoundBonePosition();
                        attackNum += 1f;
                        break;
                    case ActorState.AttackMoveForward:
                        forwardActors.Add(actor);
                        forwardSumPosition += actor.GetBeFoundBonePosition();
                        forwardNum += 1f;
                        break;
                    case ActorState.AttackMoveBackward:
                        backwardActors.Add(actor);
                        backwardSumPosition += actor.GetBeFoundBonePosition();
                        backwardNum += 1f;
                        break;
                    case ActorState.AttackReady:
                        readyActors.Add(actor);
                        readySumPosition += actor.GetBeFoundBonePosition();
                        readyNum += 1f;
                        break;
                    case ActorState.Defend:
                        var state = actor.GetCurrentState() as BCDefendState;
                        if (state.defendState != DefendState.IDLE)
                        {
                            defendSumPosition += actor.GetBeFoundBonePosition() * 1f;
                            defendNum += 1f;
                        }
                        else
                        {
                            defendSumPosition += actor.GetBeFoundBonePosition() * 0.3f;
                            defendNum += 0.3f;
                        }
                        defendActors.Add(actor);
                        break;

                }
                if (actor.isHealer)
                    healNum += 1;
            }



            activeActors.Clear();
            Vector3 averagePosition = Vector3.zero;
            float totalWeight = 0;

            averagePosition += attackSumPosition * 1.2f;
            totalWeight += attackNum * 1.2f;
            activeActors.AddRange(attackActors);

            if (defendNum > 0 && ((attackNum + forwardNum + backwardNum) > 0))
            {
                averagePosition += defendSumPosition / defendNum * 1.8f;
                totalWeight += 1.8f;
                activeActors.AddRange(defendActors);
            }
            if (attackNum == 0)
            {
                averagePosition += forwardSumPosition;
                totalWeight += forwardNum;
                activeActors.AddRange(forwardActors);
            }

            if (attackNum == 0 && forwardNum == 0)
            {
                averagePosition += backwardSumPosition;
                totalWeight += backwardNum;
                activeActors.AddRange(backwardActors);
            }

            if (healNum > 0 && readyNum > 0)
            {
                averagePosition += readySumPosition * (0.3f / readyNum);
                totalWeight += 0.3f;
                activeActors.AddRange(readyActors);
            }

            if (activeActors.Count == 0)
                return;

            averagePosition /= totalWeight;
            averagePosition.z *= 0.7f;
            averagePosition.y += actorHeight;

            targetAxis.position = new Vector3(averagePosition.x, actorHeight, averagePosition.z);

            //Vector3 leftAxisPos = Vector3.zero;
            //Vector3 rightAxisPos = Vector3.zero;
            //GetBounds(activeActors, targetAxis, out leftAxisPos, out rightAxisPos);


            //float halfFOV = (battleCamera.fieldOfView * 0.5f) * Mathf.Deg2Rad;
            //float aspect = battleCamera.aspect;

            //float k = Mathf.Tan(halfFOV) * aspect;
            //float cameraZAxisPos = Mathf.Min(leftAxisPos.z - (leftAxisPos.x - attackActorBound) / (-k), rightAxisPos.z - (rightAxisPos.x + attackActorBound) / k);
            //cameraZAxisPos = Mathf.Min(cameraZAxisPos, attackCameraZPosition);

            float cameraZAxisPos = GetCameraBattleZPos(activeActors);
            cameraZAxisPos = Mathf.Min(cameraZAxisPos, defendCameraZPosition);
            targetCamera.localPosition = new Vector3(0, 0, cameraZAxisPos);

            float sumHeight = 0;
            for (int i = 0; i < activeActors.Count; i++)
            {
                var actor = activeActors[i];
                float height = actor.GetBeFoundBonePosition().y;
                sumHeight += height;
            }
            averagePosition.y = sumHeight / activeActors.Count;
            targetCamera.LookAt(averagePosition);

            targetAxis.position -= targetCamera.up * defendAxisOffset;
        }

        #endregion update

        public void Attack()
        {
            targetAxis.localEulerAngles = attackAxisRotation;
            curState = State.Attack;
        }
        public void Defend()
        {
            targetAxis.localEulerAngles = defendAxisRotation;
            curState = State.Defend;
        }
        public void Reset()
        {
            curState = State.None;
        }

        public bool IsTraveling()
        {
            if (tweenComponet.IsPlaying())
                return true;
            return false;
        }

        #region animation

        public void StopAnim()
        {
            tweenComponet.StopAllActions();
        }

        public void PlayEnter()
        {
            //battleCamera.gameObject.SetActive(true);

            var startPos = GetCampActorAveragePosition(BattleCamp.Defender);
            startPos.y = actorHeight;
            startPos.z = startPos.z - 1f;
            curAxis.localPosition = startPos;

            curAxis.localEulerAngles = new Vector3(3, 0, 0);

            var cameraPos = Vector3.zero;
            cameraPos.z = -3f;
            curCamera.localPosition = cameraPos;

            var allActors = GetBattleViewCtrl().GetAllActors();
            float maxHeight = 0;
            foreach(var actor in allActors)
            {
                maxHeight = Mathf.Max(maxHeight, actor.Value.height);
            }
            float angle = battleCamera.fieldOfView / 2;
            float kVertical = Mathf.Tan(angle * Mathf.Deg2Rad);
            float z1 = -(maxHeight * 0.6f) / kVertical;

            float z2 = Mathf.Min(readyCameraZPosition, GetCameraReadyZPos());
            //if (z < readyCameraZPosition)
            //    readyCameraZPosition = z;

            var a11 = new TweenActionRotate(curAxis, new Vector3(4, 8f, 0), 0.3f, true);
            var a12 = new TweenActionMove(curCamera, new Vector3(0f, 0, z1-2.0f), 0.3f, true);
            var as1 = new TweenActionSpawn(new TweenActionBase[] { a11, a12 });
            var ae1 = new TweenActionCurve(as1, curveEaseOut);

            var a21 = new TweenActionRotate(curAxis, new Vector3(5, 15f, 0), 1.5f, true);
            var a22 = new TweenActionMove(curCamera, new Vector3(0f, 0, z1-2.8f), 1.5f, true);
            var as2 = new TweenActionSpawn(new TweenActionBase[] { a21, a22 });

            var a31 = new TweenActionRotate(curAxis, readyAxisRotation, 1.2f, true);
            var a32 = new TweenActionMove(curAxis, readyAxisPosition, 1.2f, true);
            var a33 = new TweenActionMove(curCamera, new Vector3(0, 0, z2), 1.2f, true);
            var as3 = new TweenActionSpawn(new TweenActionBase[] { a31, a32, a33 });
            var ae3 = new TweenActionCurve(as3, curveEaseOut);

            var aseq = new TweenActionSequence(new TweenActionBase[] { ae1, as2, ae3 });

            tweenComponet.RunAction(aseq);

        }

        public void PlayMoveToReady()
        {
            float z = Mathf.Min(readyCameraZPosition, GetCameraReadyZPos());
            //if (z < readyCameraZPosition)
            //    readyCameraZPosition = z;

            var a1 = new TweenActionRotate(curAxis, readyAxisRotation, readyMoveTime, true);
            var a2 = new TweenActionMove(curAxis, readyAxisPosition, readyMoveTime, true);
            var a3 = new TweenActionMove(curCamera, new Vector3(0, 0, z), readyMoveTime, true);
            var a4 = new TweenActionRotate(curCamera, Vector3.zero, readyMoveTime, true);
            var aspawn = new TweenActionSpawn(new TweenActionBase[] { a1, a2, a3, a4 });
            var aease = new TweenActionCurve(aspawn, curveEaseInOut);
            tweenComponet.RunAction(aease);

        }

        public void PlayUltimate(BattleCamp camp, Vector3 position,float height)
        {
            ultimateCamp = camp;

            //var view = GetBattleViewCtrl();
            Vector3 endAxisPosition = position;
            endAxisPosition.y = actorHeight;

            float angle = battleCamera.fieldOfView / 2;
            float kVertical = Mathf.Tan(angle * Mathf.Deg2Rad);
            float distanceByHeight = height / kVertical;

            switch (ultimateCamp)
            {
                case BattleCamp.Attacker:
                    {
                        //curAxis.position = endAxisPosition;
                        //curAxis.localEulerAngles = new Vector3(10f, 90f, 0);

                        var a11 = new TweenActionMove(curAxis, endAxisPosition, 0.5f, true);
                        var a12 = new TweenActionRotate(curAxis, new Vector3(10f, 165f, 0), 0.5f, true);
                        var a13 = new TweenActionMove(curCamera, new Vector3(0, 0, -distanceByHeight * 1.0f), 0.5f, true);
                        var a14 = new TweenActionRotate(curCamera, Vector3.zero, 0.5f, true);
                        var as1 = new TweenActionSpawn(new TweenActionBase[] { a11, a12, a13, a14 });

                        var a21 = new TweenActionMove(curAxis, endAxisPosition, 1.0f, true);
                        var a22 = new TweenActionRotate(curAxis, new Vector3(10f, 190f, 0), 1.0f, true);
                        var a23 = new TweenActionMove(curCamera, new Vector3(0, 0, -distanceByHeight * 0.8f), 1.0f, true);
                        var as2 = new TweenActionSpawn(new TweenActionBase[] { a21, a22, a23 });
                        var ae2 = new TweenActionCurve(as2, curveEaseOut);


                        var aseq = new TweenActionSequence(new TweenActionBase[] { as1, ae2 });

                        tweenComponet.RunAction(aseq);
                    }

                    break;
                case BattleCamp.Defender:
                    {
                        curAxis.position = endAxisPosition;
                        curAxis.localEulerAngles = new Vector3(10f, 90f, 0);
                        curCamera.localPosition = new Vector3(0, 0, -distanceByHeight * 1.1f);

                        var a11 = new TweenActionMove(curAxis, endAxisPosition, 0.7f, true);
                        var a12 = new TweenActionRotate(curAxis, new Vector3(10f, -165f - 180f, 0), 0.7f, true);
                        var a13 = new TweenActionMove(curCamera, new Vector3(0, 0, -distanceByHeight * 1.0f), 0.7f, true);
                        var a14 = new TweenActionRotate(curCamera, Vector3.zero, 0.7f, true);
                        var as1 = new TweenActionSpawn(new TweenActionBase[] { a11, a12, a13, a14 });

                        var a21 = new TweenActionMove(curAxis, endAxisPosition, 1.0f, true);
                        var a22 = new TweenActionRotate(curAxis, new Vector3(10f, -190f - 180f, 0), 1.0f, true);
                        var a23 = new TweenActionMove(curCamera, new Vector3(0, 0, -distanceByHeight * 0.8f), 1.0f, true);
                        var as2 = new TweenActionSpawn(new TweenActionBase[] { a21, a22, a23 });
                        var ae2 = new TweenActionCurve(as2, curveEaseOut);


                        var aseq = new TweenActionSequence(new TweenActionBase[] { as1, ae2 });

                        tweenComponet.RunAction(aseq);
                    }
                    break;
            }


        }

        public void Shake(int id)
        {
            shakeState = id;
            shakeTimer = 0;
        }

        /// <summary>
        /// 结算时镜头从攻击方转回
        /// </summary>
        void ReadyForUltimateEndFocusAttacker() {
            curAxis.localPosition = ultimateEndDefenderAxisPosition;
            curAxis.localEulerAngles = ultimateEndDefenderAxisRotation;
            curCamera.localPosition = new Vector3(0, 0, ultimateEndCameraZPoition);
        }
        /// <summary>
        /// 结算时镜头从防守方转回
        /// </summary>
        void ReadyForUltimateEndFocusDefender() {
            curAxis.localPosition = ultimateEndAxisPosition;
            curAxis.localEulerAngles = ultimateEndAxisRotation;
            curCamera.localPosition = new Vector3(0, 0, ultimateEndCameraZPoition);
        }
        /// <summary>
        /// 结算时镜头照全体
        /// </summary>
        void ReadyForUltimateEndFocusAll()
        {
            curAxis.localPosition = ultimateEndAllAxisPosition;
            curAxis.localEulerAngles = ultimateEndAllAxisRotation;
            curCamera.localPosition = new Vector3(0, 0, ultimateEndAllCameraZPoition);
        }

        public void PlayReadyForUltimateEnd(UltimateSkill.UltimateCameraEndType type)
        {
            switch (ultimateCamp)
            {
                case BattleCamp.Attacker:
                    if (type == UltimateSkill.UltimateCameraEndType.FocusEnemy)
                    {
                        // 从Attacker的敌方转镜头
                        ReadyForUltimateEndFocusDefender();
                    }
                    else if (type == UltimateSkill.UltimateCameraEndType.FocusMine)
                    {
                        // 从Attacker的己方转镜头
                        ReadyForUltimateEndFocusAttacker();
                    }
                    else {
                        // 照全体
                        // TEMP
                        ReadyForUltimateEndFocusDefender();
                    }
                    break;
                case BattleCamp.Defender:
                    if (type == UltimateSkill.UltimateCameraEndType.FocusEnemy)
                    {
                        // 从defender的敌方转镜头
                        ReadyForUltimateEndFocusAttacker();
                    }
                    else if (type == UltimateSkill.UltimateCameraEndType.FocusMine)
                    {
                        // 从defender的己方转镜头
                        ReadyForUltimateEndFocusDefender();
                    }
                    else {
                        // 照全体
                        // TEMP
                        ReadyForUltimateEndFocusAttacker();
                    }
                    break;
            }

        }

        /// <summary>
        /// 结算时镜头从攻击方转
        /// </summary>
        void UltimateEndFocusAttacker() {
            curAxis.localPosition = ultimateEndDefenderAxisPosition;
            curAxis.localEulerAngles = ultimateEndDefenderAxisRotation;
            curCamera.localPosition = new Vector3(0, 0, ultimateEndDefenderCameraZPoition);

            var a11 = new TweenActionRotate(curAxis, new Vector3(0, -6, 0), 0.38f, false);
            var a12 = new TweenActionMove(curCamera, new Vector3(0, 0, -1.5f), 0.38f, false);
            var as1 = new TweenActionSpawn(new TweenActionBase[] { a11, a12 });
            var ae1 = new TweenActionCurve(as1, curveEaseOut);

            var a21 = new TweenActionRotate(curAxis, new Vector3(0, -3, 0), 2.0f, false);
            var a22 = new TweenActionMove(curCamera, new Vector3(0, 0, -0.5f), 2.0f, false);
            var as2 = new TweenActionSpawn(new TweenActionBase[] { a21, a22 });
            var ae2 = new TweenActionCurve(as2, curveEaseOut);

            var seq = new TweenActionSequence(new TweenActionBase[] { ae1, ae2 });

            tweenComponet.RunAction(seq);
        }
        /// <summary>
        /// 结算时镜头从防守方转
        /// </summary>
        void UltimateEndFocusDefender() {
            curAxis.localPosition = ultimateEndAxisPosition;
            curAxis.localEulerAngles = ultimateEndAxisRotation;
            curCamera.localPosition = new Vector3(0, 0, ultimateEndCameraZPoition);

            var a11 = new TweenActionRotate(curAxis, new Vector3(0, 6, 0), 0.38f, false);
            var a12 = new TweenActionMove(curCamera, new Vector3(0, 0, -1.5f), 0.38f, false);
            var as1 = new TweenActionSpawn(new TweenActionBase[] { a11, a12 });
            var ae1 = new TweenActionCurve(as1, curveEaseOut);

            var a21 = new TweenActionRotate(curAxis, new Vector3(0, 3, 0), 2.0f, false);
            var a22 = new TweenActionMove(curCamera, new Vector3(0, 0, -0.5f), 2.0f, false);
            var as2 = new TweenActionSpawn(new TweenActionBase[] { a21, a22 });
            var ae2 = new TweenActionCurve(as2, curveEaseOut);

            var seq = new TweenActionSequence(new TweenActionBase[] { ae1, ae2 });

            tweenComponet.RunAction(seq);
        }
        /// <summary>
        /// 结算时镜头照全体
        /// </summary>
        void UltimateEndFocusAll()
        {
            curAxis.localPosition = ultimateEndAllAxisPosition;
            curAxis.localEulerAngles = ultimateEndAllAxisRotation;
            curCamera.localPosition = new Vector3(0, 0, ultimateEndAllCameraZPoition);

            var a1 = new TweenActionMove(curCamera, new Vector3(0, 0, -1.5f), 0.38f, false);
            var ae1 = new TweenActionCurve(a1, curveEaseOut);

            var a2 = new TweenActionMove(curCamera, new Vector3(0, 0, -0.5f), 2.0f, false);
            var ae2 = new TweenActionCurve(a2, curveEaseOut);

            var seq = new TweenActionSequence(new TweenActionBase[] { ae1, ae2 });

            tweenComponet.RunAction(seq);
        }

        public void PlayUltimateEnd(UltimateSkill.UltimateCameraEndType type)
        {
            switch (ultimateCamp)
            {
                case BattleCamp.Attacker:
                    if (type == UltimateSkill.UltimateCameraEndType.FocusEnemy)
                    {
                        // 从Attacker的敌方转镜头
                        UltimateEndFocusDefender();
                    }
                    else if (type == UltimateSkill.UltimateCameraEndType.FocusMine)
                    {
                        // 从Attacker的我方转镜头
                        UltimateEndFocusAttacker();
                    }
                    else {
                        // 照全体
                        // TEMP
                        UltimateEndFocusAll();
                    }
                    break;
                case BattleCamp.Defender:
                    if (type == UltimateSkill.UltimateCameraEndType.FocusEnemy)
                    {
                        // 从Defender的地方转镜头
                        UltimateEndFocusAttacker();
                    }
                    else if (type == UltimateSkill.UltimateCameraEndType.FocusMine)
                    {
                        // 从Defender的我方转镜头
                        UltimateEndFocusDefender();
                    }
                    else {
                        // 照全体
                        // TEMP
                        UltimateEndFocusAll();

                    }
                    break;
            }



        }

        public void PlayWin()
        {
            var a11 = new TweenActionMove(curAxis, winAxisPosition, winTime1, true);
            var a12 = new TweenActionRotate(curAxis, winAxisRotation1, winTime1, true);
            var a13 = new TweenActionMove(curCamera, new Vector3(0, 0, winCameraZPosition1), winTime1, true);
            var a14 = new TweenActionRotate(curCamera, Vector3.zero, winTime1, true);
            var as1 = new TweenActionSpawn(new TweenActionBase[] { a11, a12, a13, a14 });
            var ae1 = new TweenActionCurve(as1, curveEaseInOut);


            var a21 = new TweenActionRotate(curAxis, winAxisRotation2, winTime2, true);
            var a22 = new TweenActionMove(curCamera, new Vector3(0, 0, winCameraZPosition2), winTime2, true);
            var as2 = new TweenActionSpawn(new TweenActionBase[] { a21, a22 });
            var ae2 = new TweenActionCurve(as2, curveEaseOut);

            var seq = new TweenActionSequence(new TweenActionBase[] { ae1, ae2 });
            tweenComponet.RunAction(seq);
        }

        public void PlaySwitchCamp()
        {
            var a1 = new TweenActionRotate(curAxis, switchCampAxisRotation, switchCampMoveTime, true);
            var a2 = new TweenActionMove(curAxis, switchCampAxisPosition, switchCampMoveTime, true);
            var a3 = new TweenActionMove(curCamera, new Vector3(0, 0, switchCampCameraZPosition), switchCampMoveTime, true);
            var a4 = new TweenActionRotate(curCamera, Vector3.zero, switchCampMoveTime, true);
            var aspawn = new TweenActionSpawn(new TweenActionBase[] { a1, a2, a3, a4 });
            var aease = new TweenActionCurve(aspawn, curveEaseInOut);
            tweenComponet.RunAction(aease);
        }

        #endregion animation

        #region focus

        public void SetFocusGameObject(GameObject obj)
        {
            CommonMethod.ChangeLayer(obj.transform, "OnlyFocus");
            onlyFocusCamera.gameObject.SetActive(true);
            focusCamera.gameObject.SetActive(false);
            blackPlane.gameObject.SetActive(true);
        }
        public void SetUnfocusGameObject(GameObject obj, int layer)
        {
            CommonMethod.ChangeLayer(obj.transform, layer);
            onlyFocusCamera.gameObject.SetActive(false);
            focusCamera.gameObject.SetActive(false);
            blackPlane.gameObject.SetActive(false);
        }

        public void SetFocusBattleCharacter(GameObject obj, float delay = 0f)
        {
            CommonMethod.ChangeLayer(obj.transform, "SceneActorFocus");
            focusCamera.gameObject.SetActive(true);
            onlyFocusCamera.gameObject.SetActive(false);
            blackPlane.gameObject.SetActive(true);
            if (delay > 0f)
            {
                StopCoroutine("_RevertFocusGameObject");
                StartCoroutine(_RevertFocusBattleCharacter(delay, obj));
            }
        }

        IEnumerator _RevertFocusBattleCharacter(float delay, GameObject obj)
        {
            yield return new WaitForSeconds(delay);
            CommonMethod.ChangeLayer(obj.transform, "SceneActor");
            obj.GetComponent<ModelRenderKit>().SetWeaponEffectLayer("SceneParticle");
            focusCamera.gameObject.SetActive(false);
            onlyFocusCamera.gameObject.SetActive(false);
            blackPlane.gameObject.SetActive(false);
        }

        public void SetUnFocusBattleCharacter(GameObject obj)
        {
            CommonMethod.ChangeLayer(obj.transform, "SceneActor");
            obj.GetComponent<ModelRenderKit>().SetWeaponEffectLayer("SceneParticle");
            focusCamera.gameObject.SetActive(false);
            onlyFocusCamera.gameObject.SetActive(false);
            blackPlane.gameObject.SetActive(false);
        }

        #endregion focus


        #region help

        public BattleViewCtrl GetBattleViewCtrl()
        {
            return BattleViewCtrl.GetInstance();
        }

        public Vector3 GetCampActorAveragePosition(BattleCamp camp)
        {
            var battleView = GetBattleViewCtrl();
            var guids = battleView.GetActorUids(camp);
            var allActors = battleView.GetAllActors();
            Vector3 p = new Vector3();
            float n = 0;
            foreach (var guid in guids)
            {
                var bc = allActors[guid];
                if (bc.isAlive)
                {
                    p += bc.GetBeFoundBonePosition();
                    n++;
                }

            }
            p /= n;
            return p;
        }

        private float GetCameraReadyZPos()
        {
            var battleView = GetBattleViewCtrl();
            var allActors = battleView.GetAllActors();

            tmpTransform.localPosition = readyAxisPosition;
            tmpTransform.localEulerAngles = readyAxisRotation;
            tmpTransform.localScale = Vector3.one;

            float angle = battleCamera.fieldOfView / 2;
            float kVertical = Mathf.Tan(angle * Mathf.Deg2Rad);
            float kHorizontal = kVertical * battleCamera.aspect;

            float minZ = 0f;

            foreach (var actor in allActors.Values)
            {
                float tmpZ = GetMinZPosition(tmpTransform, actor.GetStandPosition(), actor.height, readyActorBound, kHorizontal, kVertical);
                minZ = Mathf.Min(minZ, tmpZ);
            }
            return minZ;

        }

        private float GetCameraBattleZPos(List<BattleCharacter> allActors)
        {

            float angle = battleCamera.fieldOfView / 2;
            float kVertical = Mathf.Tan(angle * Mathf.Deg2Rad);
            float kHorizontal = kVertical * battleCamera.aspect;

            float minZ = 0f;

            for (int i = 0; i < allActors.Count; i++)
            {
                var actor = allActors[i];
                float height = Mathf.Max(actor.height, actor.height * 0.5f + (actor.GetBeFoundBonePosition().y - actor.transform.position.y));
                float tmpZ = GetMinZPosition(targetAxis, actor.transform.position, height, attackActorBound, kHorizontal, kVertical);
                minZ = Mathf.Min(minZ, tmpZ);
            }
            return minZ;
        }

        private float GetMinZPosition(Transform axis, Vector3 pos, float modelHeight, float modelBound, float kHorizontal, float kVertical)
        {
            Vector3 enemyAxisPosHeight = axis.InverseTransformPoint(pos + new Vector3(0, modelHeight, 0));
            Vector3 enemyAxisPos = axis.InverseTransformPoint(pos);
            //float enemyAxisAngle = Vector2.Angle(enemyAxisPos, Vector2.up);
            float minZ = 0f;
            float tmpZ;
            float boundZ = modelBound / kHorizontal;
            {
                {
                    tmpZ = (enemyAxisPos.z - (enemyAxisPos.x) / (-kHorizontal));
                    tmpZ -= boundZ;
                }
                minZ = Mathf.Min(minZ, tmpZ);

                {
                    tmpZ = (enemyAxisPos.z - (enemyAxisPos.x) / (kHorizontal));
                    tmpZ -= boundZ;
                }
                minZ = Mathf.Min(minZ, tmpZ);

                if (minZ > (enemyAxisPos.z - (enemyAxisPosHeight.y) / (kVertical)))
                    minZ = enemyAxisPos.z - (enemyAxisPosHeight.y) / (kVertical);

                if (minZ > (enemyAxisPos.z - (enemyAxisPos.y + 0) / (-kVertical)))
                    minZ = enemyAxisPos.z - (enemyAxisPos.y + 0) / (-kVertical);
            }
            return minZ;
        }

        //void GetBounds(List<BattleCharacter> actors, Transform axis, out Vector3 leftAxisPos, out Vector3 rightAxisPos)
        //{
        //    leftAxisPos = Vector3.zero;
        //    rightAxisPos = Vector3.zero;
        //    for (int i = 0; i < actors.Count; i++)
        //    {
        //        Vector3 actorAxisPos = axis.InverseTransformPoint(actors[i].GetBeFoundBonePosition());
        //        if (leftAxisPos.x > actorAxisPos.x)
        //        {
        //            leftAxisPos = actorAxisPos;
        //        }
        //        if (rightAxisPos.x < actorAxisPos.x)
        //        {
        //            rightAxisPos = actorAxisPos;
        //        }
        //    }
        //}

        private Vector3 GetNearAngle(Vector3 ori)
        {
            Vector3 result = Vector3.zero;
            result.x = GetNearAngle(ori.x);
            result.y = GetNearAngle(ori.y);
            result.z = GetNearAngle(ori.z);
            return result;
        }
        //获得-180到180度的值
        private float GetNearAngle(float ori)
        {
            float floor = Mathf.Floor(ori / 360);
            ori -= floor * 360f;
            if (ori > 180f)
                ori -= 360f;
            return ori;
        }

        #endregion
    }
}
